package com.yanqu.road.server.manager.config;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.dao.impl.config.ConfigDaoImpl;
import com.yanqu.road.dao.impl.systemloop.CrossSystemLoopDaoImpl;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.servercenter.SystemLoopConfig;
import com.yanqu.road.entity.systemloop.SystemLoopData;
import com.yanqu.road.entity.union.cross.CrossUnionServerGroup;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.redis.RedisKeyDefine;
import com.yanqu.road.logic.redis.RedisKeyDefineHelper;
import com.yanqu.road.logic.redis.RedisManger;
import com.yanqu.road.pb.server.ServerProto;
import com.yanqu.road.reids.subpub.eRedisChannelType;
import com.yanqu.road.server.TempCrossMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manger.CrossUnionServerGroupMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.config.Config;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;

public class CrossSystemLoopMgr extends TempCrossMgr {
    private static Map<Integer, SystemLoopConfig> loopConfigMap = new HashMap<>();
    private static Map<Integer, SystemLoopData> loopDataMap = new HashMap<>();
    //key systemId
    private static Map<Integer, List<SystemLoopConfig>> systemLoopConfigMap = new HashMap<>();
    private static int lastCheckWeekId;
    private static Object lock = new Object();

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        Map<Integer, SystemLoopConfig> tempConfigMap = new ConfigDaoImpl().getSystemLoopConfigMap(ConfigHelper.getInt("channelId"));
        Map<Integer, List<SystemLoopConfig>> tempSystemLoopConfigMap = new HashMap<>();
        for (SystemLoopConfig loopConfig : tempConfigMap.values()) {
            for (Integer systemId : loopConfig.getSystemIdList()) {
                List<SystemLoopConfig> systemLoopConfigs = tempSystemLoopConfigMap.get(systemId);
                if (systemLoopConfigs == null) {
                    systemLoopConfigs = new ArrayList<>();
                    tempSystemLoopConfigMap.put(systemId, systemLoopConfigs);
                }
                systemLoopConfigs.add(loopConfig);
            }
        }

        loopConfigMap = tempConfigMap;
        systemLoopConfigMap = tempSystemLoopConfigMap;
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        getLogger().info("CrossSystemLoopMgr reloadData start");
        Map<Integer, SystemLoopData> tempDataMap = new CrossSystemLoopDaoImpl().getSystemLoopData();
        loopDataMap = tempDataMap;

        for (SystemLoopData loopData : loopDataMap.values()) {
            getLogger().info("reloadData loopData systemId:{}", loopData.getSystemId());
        }

        Set<Integer> needRemoveLoopId = new HashSet<>();
        //最近一次更新的周id
        for (SystemLoopData loopData : loopDataMap.values()) {
            if (lastCheckWeekId == 0) {
                lastCheckWeekId = loopData.getLastWeekId();
            }
            if (loopData.getLastWeekId() < lastCheckWeekId) {
                lastCheckWeekId = loopData.getLastWeekId();
            }

            if (!loopConfigMap.containsKey(loopData.getLoopId())) {
                needRemoveLoopId.add(loopData.getLoopId());
            }
        }

        //移出没配置的数据
        for (Integer loopId : needRemoveLoopId) {
            loopDataMap.remove(loopId);
        }

        lastCheckWeekId = 0;
        checkSystemLoop(true);

        getLogger().info("CrossSystemLoopMgr reloadData end");
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean save() {
        List<SystemLoopData> list = new ArrayList<>(loopDataMap.values());
        for (SystemLoopData loopData : list) {
            if (loopData.isInsertOption()) {
                new CrossSystemLoopDaoImpl().add(loopData);
            } else if (loopData.isUpdateOption()) {
                new CrossSystemLoopDaoImpl().update(loopData);
            }
        }

        return true;
    }

    public static List<ServerInfo> getLoopServerList(int systemId) {
        if (!CrossSystemSwitchMgr.isSystemOpen(systemId)) {
            return new ArrayList<>();
        }

        List<SystemLoopConfig> systemLoopConfigs = systemLoopConfigMap.get(systemId);
        if (systemLoopConfigs == null) {
            return new ArrayList<>();
        }

        Set<Long> openServerList = new HashSet<>();

        for (SystemLoopConfig loopConfig : systemLoopConfigs) {
            SystemLoopData loopData = getSystemLoopData(loopConfig.getId());
            if (loopData == null) {
                continue;
            }
            if (loopData.getSystemId() != systemId){
                continue;
            }

            openServerList.addAll(loopData.getServerIdSet());
        }
        List<ServerInfo> needServerList = new ArrayList<>();
        for (Long serverId : openServerList) {
            ServerInfo serverInfo = ServerListMgr.getServerInfo(serverId);
            if (serverInfo == null) {
                continue;
            }
            if (CrossSystemSwitchMgr.isServerLockSystem(serverInfo.getServerId(), systemId)){
                continue;
            }
            needServerList.add(serverInfo);
        }

        return needServerList;
    }

    public static SystemLoopData getSystemLoopData(int loopId) {
        SystemLoopData systemLoopData = loopDataMap.get(loopId);
        if (systemLoopData == null) {
            synchronized (loopDataMap) {
                systemLoopData = loopDataMap.get(loopId);
                if (systemLoopData == null) {
                    systemLoopData = new SystemLoopData(loopId);
                    loopDataMap.put(loopId, systemLoopData);
                }
            }
        }
        return systemLoopData;
    }


    @Override
    public boolean removeExpireData() throws Exception {
        return false;
    }

    public static void checkSystemLoop(boolean isReload) {
        synchronized (lock){
            int thisWeekId = GameConfig.getSystemThisWeekId();
            if (thisWeekId == lastCheckWeekId) {
                return;
            }
            getLogger().info("开始系统轮换");

            long thisWeekStartTime = DateHelper.getThisWeekStartTime(GameConfig.DAY_SYSTEM_RESET_TIME);

            List<ServerInfo> openServerList = new ArrayList<>();
            Map<Long, SystemLoopData> serverSystemIdsMap = new HashMap<>();
            //测试用配置
            String testActivityServerId = ConfigHelper.getValue("testActivityServerId");
            if (!StringUtils.isNullOrEmpty(testActivityServerId)) {
                List<Long> serverIds = StringUtils.stringToLongList(testActivityServerId, ";");
                if(Config.isDebug()) {
                    serverIds = StringUtils.stringToLongList("88882,10100001,15100001,16000001,16000002,16000003,16300001,16300002,16300003,50900100,50900200,50901200,50901300,66600001,66600002,66600011,66600012,66600021,66600022,66600031,66600032,66600041,66600042,66600051,66600052,66600061,66600062,66601001,88800000,88800001,88800002,88800003,99900002,99900003,99900004,99900005,99900006,99900007,99900008,99900009,99900011,99900012,99900013,99900014,99900015,99900016,99900017,99900018,99900019,99900023,99900024,99900025,99900026,99900027,99900028,99900029,99900032,99900033,99900035,99900040,99900041,99900045,99900046,99900047,99900061,99900065,99900069,99900073,99900074,99900077,99900078,99900100,99900113,99900134,99900135,99900136,99900137,99900326,99900327,99900523,99900524,99900525,99900670,99900671,99900677,99900678,99900679,99900777,99900888,99900997,99900998,99900999,99901004,99901005,99901006,99901007,99901008,99901009,99901010,99901011,99901012,99901013,99901026,99901027,99901028,99901221,99901222,99902001,99902002,99902003,99902004,99903001,99903002,99903003,99903328,99903917,99905001,99905002,99905003,99906601,99906602,99908193,99908194,99908195,99908661,99908662,99908663,99908807,99908808,99908809,99911127,99933001,99933002,99933010,99946661,99946662,99946663,99996661,99996662,99996663,666888001,666888002,666888003,999008882,999024580,2147483647", ",");
                }
                for (Long serverId : serverIds) {
                    ServerInfo serverInfo = ServerListMgr.getServerInfo(serverId);
                    if(serverInfo == null){
                        continue;
                    }
                    openServerList.add(serverInfo);
                }
            } else {
                openServerList = ServerListMgr.getOpenServerList(ConfigHelper.getInt("channelId"));
            }
            List<SystemLoopConfig> configList = new ArrayList<>(loopConfigMap.values());
            Set<Long> includeServerIds = new HashSet<>();
            //configList倒序遍历
            for (int i = configList.size() - 1; i >= 0; i--) {
                SystemLoopConfig loopConfig = configList.get(i);
                SystemLoopData loopData = getSystemLoopData(loopConfig.getId());
                if (loopData == null) {
                    continue;
                }
                int nowSystemId = loopData.getSystemId();
                if (loopData.getLastWeekId() != thisWeekId) {
                    nowSystemId = loopConfig.getNextSystemId(loopData.getSystemId());
                    if (!CrossSystemSwitchMgr.isSystemOpen(nowSystemId)) {
                        nowSystemId = 0;
                        //获得下一个开启的系统id,最多遍历list.size()次
                        for (int j = 0; j < loopConfig.getSystemIdList().size(); j++) {
                            nowSystemId = loopConfig.getNextSystemId(nowSystemId);
                            if (CrossSystemSwitchMgr.isSystemOpen(nowSystemId)) {
                                break;
                            }
                        }

                    }
                }

                loopData.setSystemId(nowSystemId);
                loopData.setServerIdSet(new HashSet<>());
                loopData.setLastWeekId(thisWeekId);
                eSystemId eType = eSystemId.forValue(nowSystemId);
                if (eType == null) {
                    getLogger().info("配置id={},轮换不到系统={}", loopConfig.getId(), nowSystemId);
                    continue;
                }
                getLogger().info("配置id={},轮换到系统={}", loopConfig.getId(), nowSystemId);
                //key 商会分组id, value 服务器数量;超过50%的才放进去
                Map<Integer, Integer> unionGroupServerNumMap = new HashMap<>();
                for (ServerInfo serverInfo : openServerList) {
                    if (includeServerIds.contains(serverInfo.getServerId())) {
                        continue;
                    }
                    int openDay = ServerListMgr.getServerOpenDayByTime(serverInfo, thisWeekStartTime);
                    if (openDay >= loopConfig.getStartDay() && openDay <= loopConfig.getEndDay()) {

                        CrossUnionServerGroup unionServerGroup = CrossUnionServerGroupMgr.getServerGroupByServerId(serverInfo.getServerId());
                        if (unionServerGroup != null) {
                            Integer serverNum = unionGroupServerNumMap.getOrDefault(unionServerGroup.getGroupId(), 0);
                            serverNum++;
                            unionGroupServerNumMap.put(unionServerGroup.getGroupId(), serverNum);
                        } else {
                            loopData.addServerId(serverInfo.getServerId());
                            includeServerIds.add(serverInfo.getServerId());

                            serverSystemIdsMap.put(serverInfo.getServerId(), loopData);
                        }
                    }
                }

                //超过50%的拉到一起
                for (Map.Entry<Integer, Integer> entry : unionGroupServerNumMap.entrySet()) {
                    Integer groupId = entry.getKey();
                    CrossUnionServerGroup serverGroup = CrossUnionServerGroupMgr.getServerGroup(groupId);
                    if (serverGroup == null) {
                        continue;
                    }
                    int totalNum = serverGroup.getServerList().size();
                    int serverNum = entry.getValue();
                    if (serverNum * 1000 / totalNum >= 500) {
                        for (Long serverId : serverGroup.getServerList()) {
                            if (serverSystemIdsMap.containsKey(serverId)) {//先后顺序问题,可能已经被其他系统拉过了
                                SystemLoopData checkLoopData = serverSystemIdsMap.get(serverId);
                                checkLoopData.removeServerId(serverId);
                                serverSystemIdsMap.remove(serverId);
                            }

                            loopData.addServerId(serverId);
                            includeServerIds.add(serverId);

                            serverSystemIdsMap.put(serverId, loopData);
                        }
                        getLogger().info("配置id={},系统={},商会跨服分组={},区间内区服数{}超过{}的50%,拉到一起", loopConfig.getId(), nowSystemId, groupId, serverNum, totalNum);
                    }
                }
                getLogger().info("配置id={},系统={},区间内区服={}", loopConfig.getId(), nowSystemId, JSON.toJSONString(loopData.getServerIdSet()));
            }

            lastCheckWeekId = thisWeekId;
            getLogger().info("系统轮换结束");

            //redis更新数据和广播
            int channelId = ConfigHelper.getInt("channelId");
            RedisManger.getRedisUtil().setString(RedisKeyDefineHelper.getChannelSystemLoopKey(ConfigHelper.getInt("channelId")), JSON.toJSONString(loopDataMap));
            Long count = RedisManger.getRedisUtil().publish(eRedisChannelType.SystemConfig.getChannel(), RedisKeyDefineHelper.getChannelLoopPublishMsg(channelId));

            //广播
            if (!isReload) {
                for (Map.Entry<Long, SystemLoopData> entry : serverSystemIdsMap.entrySet()) {
                    long serverId = entry.getKey();
                    SystemLoopData loopData = entry.getValue();
                    ServerProto.CrossSyncSystemLoopMsg.Builder synMsg = ServerProto.CrossSyncSystemLoopMsg.newBuilder();
                    ServerProto.SystemLoopSyncMsg.Builder builder = ServerProto.SystemLoopSyncMsg.newBuilder();
                    builder.addSystemId(loopData.getSystemId());
                    synMsg.setSyncMsg(builder);
                    MessageHelper.sendPacket(serverId, 0,
                            YanQuMessageUtils.buildMessage(GameProtocol.S_SYSTEM_LOOP_SYNC_FROM_CROSS, synMsg));
                }
            }
        }
    }

    public static List<Integer> getNowWeekSystemIds(long serverId) {
        List<Integer> systemIdList = new ArrayList<>();
        int weekId = GameConfig.getSystemThisWeekId();
        for (SystemLoopData loopData : loopDataMap.values()) {
            if(loopData.getLastWeekId() != weekId){
                continue;
            }
            if (loopData.getServerIdSet().contains(serverId)) {
                systemIdList.add(loopData.getSystemId());
            }
        }

        return systemIdList;
    }

}
